package com.ld.common.tag;

import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.ld.admin.util.PermissionUtil;
import com.ld.shieldsb.common.core.util.StringUtils;

import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * 权限判断标签
 * 
 * @ClassName QueryParamTag
 * @author <a href="mailto:donggongai@126.com" target="_blank">吕凯</a>
 * @date 2019年3月28日 下午3:54:16
 *
 */
@EqualsAndHashCode(callSuper = false)
@Data
public class PermssionTag extends SimpleTagSupport {

    private String value;// 传入的值
    private String type;// 权限位置类型：topMenu，leftMenu，button
    Map<String, Boolean> permCachePageId = new HashMap<>(); // 权限缓存，同一请求不用进行多次查询
    Map<String, Boolean> permCacheURL = new HashMap<>(); // 权限缓存，同一请求不用进行多次查询

    @Override
    public void doTag() throws JspException, IOException {
        JspWriter out = this.getJspContext().getOut();// 指定输入流
        HttpServletRequest request = (HttpServletRequest) ((PageContext) this.getJspContext()).getRequest();
        JspFragment jf = this.getJspBody();
        StringWriter sw = new StringWriter();
        jf.invoke(sw);

        String content = sw.getBuffer().toString();
        if (content != null && PermissionUtil.checkPermission(request)) { // 内容不为空并且需要检查权限的
            content = content.replaceAll("\\<!--(.+)--\\>", ""); // 去除注释
            if ("topMenu".equals(type)) { // 头部菜单
                Document doc = Jsoup.parse(content);
                Elements eles = doc.select("[permId]");
                int eleSize = eles.size();
                if (eleSize > 0) { // 存在
                    dealHtmlEle(request, eles);
                    content = getHtml(doc);
                }

            } else if ("leftMenu".equals(type)) { // 左侧菜单
                Document doc = Jsoup.parse(content);
                Elements eles = doc.select("[permfor]"); // 1、首先判断左侧菜单关联的顶部菜单【模块】是否有权限，如果topMenu无权限则此项直接移除
                int eleSize = eles.size();
                if (eleSize > 0) { // 存在
                    for (Element ele : eles) {
                        String topMenu = ele.attr("permfor"); // 父权限
                        boolean hasPerm = checkElePerm(request, ele, topMenu, null);
                        if (!hasPerm) {
                            ele.remove();
                            continue; // 移除就不需要进行后面的验证了
                        }
                        // 2、然后验证里面菜单的权限
                        Elements childEles = ele.select("[permId]");
//                        dealHtmlEle(request, userPermIds, childEles);
                        int childElesSize = childEles.size();
                        if (childElesSize > 0) { // 存在
                            childEles.forEach(childEle -> {
                                String permId = childEle.attr("permId");
                                boolean hasPermChild = checkElePerm(request, childEle, permId, null);
                                if (!hasPermChild) {
                                    Element parentE = childEle.parent(); // 放到前面，后面可能出现空指针
                                    childEle.remove();

                                    // 以下内容跟页面结构有关，页面调整时注意修！！！
                                    int childNodeSize = parentE.select("li").size();
                                    if (childNodeSize == 0) {
                                        Element prevEle = parentE.previousElementSibling();
                                        if (prevEle != null) {
                                            Boolean isTitleEle = prevEle.hasClass("sub_title");
                                            if (isTitleEle) {
                                                prevEle.remove(); // 移除标题栏
                                            }
                                        }
                                        parentE.remove(); // 移除父ul
                                    }
                                }

                            });
                        }
                    }
                    content = getHtml(doc);
                }

            } else if ("button".equals(type)) { // 按钮
                Document doc = Jsoup.parse(content);
                Elements eles = doc.select("[data-url],[permId],[action],[href]"); // 有data-url或者permId属性的
                int eleSize = eles.size();
                if (eleSize > 0) { // 存在
                    dealHtmlEle(request, eles);
                    content = getHtml(doc);
                }

            }
        }
        out.print(content);
        permCachePageId.clear();
        permCacheURL.clear();
    }

    private String getHtml(Document doc) {
        doc.outputSettings().prettyPrint(false); // 不格式化，返回原始内容
        String content = doc.body().html();
        return content;
    }

    /**
     * 
     * 处理元素
     * 
     * @Title dealHtmlEle
     * @author 吕凯
     * @date 2019年4月2日 上午11:12:39
     * @param request
     * @param userPermIds
     * @param childEles
     *            void
     */
    private void dealHtmlEle(HttpServletRequest request, Elements childEles) {
        int childElesSize = childEles.size();
        if (childElesSize > 0) { // 存在
            childEles.forEach(childEle -> {
                String dataUrl = childEle.attr("data-url"); // 优先取data-url
                if (StringUtils.isBlank(dataUrl)) {
                    dataUrl = childEle.attr("href"); // href
                }
                if (StringUtils.isBlank(dataUrl)) {
                    dataUrl = childEle.attr("action"); // form的action
                }
                String permId = childEle.attr("permId");
                boolean hasPerm = checkElePerm(request, childEle, permId, dataUrl);
                if (!hasPerm) {
                    Element parentE = childEle.parent(); // 放到前面，后面可能出现空指针
                    childEle.remove();

                    // 父类为空则移除
                    int childNodeSize = parentE.childNodeSize();
                    if (childNodeSize == 0) {
                        parentE.remove(); // 移除父ul
                    }
                }

            });
        }
    }

    /**
     * 检测元素是否符合权限
     * 
     * @Title checkElePerm
     * @author 吕凯
     * @date 2019年4月2日 上午11:16:31
     * @param request
     * @param userPermIds
     * @param childEle
     * @param pageId
     *            判断pageId
     * @param dataUrl
     *            判断dateUrl void
     */
    private boolean checkElePerm(HttpServletRequest request, Element childEle, String pageId, String dataUrl) {
        boolean hasPageId = false;
        if (StringUtils.isNotBlank(pageId)) {
            hasPageId = true;
        }
        Boolean cache = gethasPermFromCache(hasPageId, pageId, dataUrl); // 先从缓存中取
        if (cache != null) { // 缓存中存在则直接返回，否则继续后面的处理
            return cache;
        }
        boolean result = PermissionUtil.checkElePerm(request, childEle, pageId, dataUrl);
        putHasPerm2Cache(hasPageId, pageId, dataUrl, result); // 放入缓存
        return result;
    }

    /**
     * 
     * 放入缓存
     * 
     * @Title putHasPerm2Cache
     * @author 吕凯
     * @date 2019年4月2日 下午5:25:13
     * @param hasPageId
     * @param pageId
     * @param dataUrl
     * @param cacheValue
     *            缓存的值
     * @return void
     */
    private void putHasPerm2Cache(boolean hasPageId, String pageId, String dataUrl, boolean cacheValue) {
        if (hasPageId) {
            permCachePageId.put(pageId, cacheValue);
        } else {
            permCacheURL.put(dataUrl, cacheValue);
        }
    }

    /**
     * 获取缓存
     * 
     * @Title getCache
     * @author 吕凯
     * @date 2019年4月2日 下午5:29:44
     * @param hasPageId
     *            是否存在pageId
     * @param pageId
     * @param dataUrl
     * @return Boolean
     */
    private Boolean gethasPermFromCache(boolean hasPageId, String pageId, String dataUrl) {
        Boolean childPermModle = null;
        if (hasPageId) {
            childPermModle = permCachePageId.get(pageId);
        } else {
            childPermModle = permCacheURL.get(dataUrl); // 存在权限
        }
        return childPermModle;
    }

}
